package r25.room;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;

import r25.board.RoomPosition;
import r25.character.ICharacter;
import r25.character.IInRoomObject;
import r25.character.ReminderToken;
import r25.engine.Event;
import r25.engine.IEvent;
import r25.engine.IEvent.EVENT;
import r25.engine.IGameInstance;
import r25.engine.IGameInstance.CHARACTER_ACTION;
import r25.tools.IdGenerator;
import r25.tools.LoggerHelper;
import r25.tools.ParameterHelper2;

public abstract class AbstractRoom implements IRoom {
	private static final Logger logger = LoggerHelper.getLogger();

	private final Map<String, Object> parameters = new HashMap<String, Object>();
	private final String id;
	private String name;
	private String description;
	private DANGER_LEVEL dangerLevel;
	private INITIAL_RANDOM_SET initialRandomSet;
	private int posX;
	private int posY;
	private boolean visible;
	private final boolean accessible;

	public AbstractRoom() {
		id = IdGenerator.createId();
		accessible = true;
	}

	@Override
	public void parameter(Map<String, Object> p) throws Exception {
		parameters.putAll(p);
		name = (String) parameters.get("name");
		description = (String) parameters.get("description");
		dangerLevel = DANGER_LEVEL.valueOf((String) parameters
				.get("dangerLevel"));
		initialRandomSet = INITIAL_RANDOM_SET.valueOf((String) parameters
				.get("initialRandomSet"));
	}

	@Override
	public Map<String, Object> getParameters() {
		return parameters;
	}

	@Override
	public void setName(String name) {
		this.name = name;
	}

	@Override
	public void setDescription(String description) {
		this.description = description;
	}

	@Override
	public void setDangerLevel(DANGER_LEVEL dl) {
		dangerLevel = dl;
	}

	@Override
	public String getId() {
		return id;
	}

	@Override
	public String getName() {
		return name;
	}

	@Override
	public String getDescription() {
		return description;
	}

	@Override
	public DANGER_LEVEL getDangerLevel() {
		return dangerLevel;
	}

	@Override
	public INITIAL_RANDOM_SET getInitialRandomSet() {
		return initialRandomSet;
	}

	@Override
	public void setInitialRandomSet(INITIAL_RANDOM_SET initialRandomSet) {
		this.initialRandomSet = initialRandomSet;
	}

	@Override
	public RoomPosition getRoomPosition() {
		return new RoomPosition(posX, posY);
	}

	@Override
	public int getPosX() {
		return posX;
	}

	@Override
	public void setPosX(int posX) {
		this.posX = posX;
	}

	@Override
	public int getPosY() {
		return posY;
	}

	@Override
	public void setPosY(int posY) {
		this.posY = posY;
	}

	@Override
	public boolean isVisible() {
		return visible;
	}

	@Override
	public void setVisible(boolean visible) {
		this.visible = visible;
	}

	@Override
	public boolean canBeControlled() {
		return true;
	}

	@Override
	public boolean canBeSwitched() {
		return true;
	}

	@Override
	public boolean isAccessible() {
		return accessible;
	}

	@Override
	public String toString() {
		return "[ " + name + ":" + id + " X:" + posX + " Y:" + posY
				+ " danger:" + dangerLevel + " initialRandomSet:"
				+ initialRandomSet + " ]";
	}

	@Override
	public int hashCode() {
		return this.getId().hashCode();
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if ((obj == null) || (this.getClass() != obj.getClass()))
			return false;

		IRoom ro = (IRoom) obj;

		return this.getId().equals(ro.getId());
	}

	@Override
	public IRoom newInstance() {
		try {
			return ParameterHelper2.newInstance(parameters);
		} catch (Exception e) {
			logger.error("", e);
		}
		return null;
	}

	@Override
	public void onReveal(IGameInstance gi, ICharacter character)
			throws Exception {
		gi.pushEvent(new Event(EVENT.REVEAL_ROOM, this, character));

		List<IInRoomObject> iros = gi.getInRoomObjects(this, true);
		logger.debug("onReveal InRoomObjects: {}", iros);
		for (IInRoomObject iro : iros) {
			if (iro instanceof ReminderToken) {
				ReminderToken rt = (ReminderToken) iro;
				rt.bringBackToOwner();

				gi.pushEvent(new Event(EVENT.BRING_BACK_REMINDER_TOKEN, this,
						rt.getOwner()));
			}
		}
	}

	@Override
	public CHARACTER_ACTION onEnter(IGameInstance gi, ICharacter character)
			throws Exception {
		gi.pushEvent(new Event(EVENT.ENTER_ROOM, this, character));

		if (!isVisible()) {
			setVisible(true);
			onReveal(gi, character);
		}
		return null;
	}

	@Override
	public int countCharacterActions() {
		return 2;
	}

	@Override
	public List<CHARACTER_ACTION> availableCharacterActions() {
		List<CHARACTER_ACTION> rc = new ArrayList<CHARACTER_ACTION>();
		for (CHARACTER_ACTION ca : CHARACTER_ACTION.values()) {
			rc.add(ca);
		}
		return rc;
	}

	@Override
	public void check(IGameInstance gi, boolean endOfTurn, IEvent s) {
		// only Room25 should take care of ROOM_OUT_OF_COMPLEX
		if (EVENT.ROOM_OUT_OF_COMPLEX.equals(s.getType())) {
			s.setValid(false);
		}
	}
}
